perm filename 4RADD.OLD[HAL,HE] blob
sn#116207 filedate 1974-08-20 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00011 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 This file holds new, untried sections for 4R.DOC.
C00003 00003 CONTROL STRUCTURES now in memo
C00007 00004 PROCEDURES now in memo
C00013 00005 CONSTANT VELOCITY MOTION now in memo
C00015 00006 LIBRARY ROUTINES now in memo
C00022 00007 IMPLEMENTATION OF ON-MONITORS
C00025 00008 INTERPRETER CODE FOR MOTIONS
C00027 00009 THE INTERPRETER SCHEDULER
C00036 00010 DEPROACHES now in memo
C00044 00011 SYSTEM USER FEATURES
C00053 ENDMK
C⊗;
This file holds new, untried sections for 4R.DOC.
The oontents are open for discussion.
CONTROL STRUCTURES now in memo
PROCEDURES now in memo
CONSTANT VELOCITY MOTION now in memo
LIBRARY ROUTINES now in memo
IMPLEMENTATION OF ON-MONITORS
This page is a set of notes for the eventual documentation.
Author: RF
The code for an on-monitor is in-line and jumped around.
The code is PDP11 code, including calls on arithmetic subroutines,
if neccessary.
Each on-monitor is given a unique name by the compiler.
The scheduler associates that name with the location of the
enable bit for this monitor.
On-monitors have only two states: enabled and disabled.
There is a status word associated with each on-monitor;
it contains two bits: the enabled, and the kill.
At the start of a program, all on-monitors are disabled.
That means enable=0, kill=0.
At the end of a block, the compiler includes code to disable all
on-monitors within that block.
Only one copy of an on-monitor ever exists. No multiple instantiations.
ENABLE <NAME>
To enable a software monitor,
tell kernel to activate it at its address, in on-level, where
it will have PDP11 code to:
1) look at its "enabled bit". If already on, dismiss. If not, turn on.
2) clear all its working buffers (if any)
3) schedule its second entry (the monitor itself) to be awakened at
the appropriate intervals. Then dismiss.
The software monitor, every time it is awakened, does the following:
1) look at its "kill bit". If on, clear and dismiss.
2) execute the code for its check.
3) if condition satisfied, do immediate stuff,
instantiate the conclusion, and dismiss.
4) reschedule self at appropriate interval. Dismiss.
To enable a hardware monitor,
tell kernel to activate it at its address, in on-level, where
it will have PDP11 code to:
1) look at the device enabled bit. If already on, return. If not, turn on.
2) dismiss.
DISABLE <NAME>
To disable a software monitor, set its "kill bit".
To disable a hardware monitor, clear its "enabled bit".
INTERPRETER CODE FOR MOTIONS
not yet ready. Author: RF.
The code generated for a move includes the following interpreter commands:
1) Prepare move. This points to the move table, and causes the trajectory
to be modified to conform to current locations of via points. Joint
loading is calculated for each via point as well.
2) Enable on-monitor. There may be more than one of these instructions.
3) Start motion. This points to the modified move table.
4) Await completion. This causes the interpreter to wait until the
move has completed, or the arm has been stopped for some reason.
The signal which awakes the interpreter comes from whichever joint
servo finishes last: each servo, as it finishes, checks to see if all
the others are done, and if so, awakes the interpreter at servo level.
5) disable all on-monitors associated with move. This is done at
servo level
6) dismiss to interpreter level.
THE INTERPRETER SCHEDULER
The interpreter scheduler is a set of routines used for
handling interpreter sprouting, termination, waiting, and scheduling,
and for on-monitor enabling and disabling. The code "↑" means
switch to high priority (above any on-monitor); the code "↓" means
return to previous priority.
RCLASS ONID (INTEGER STATUS, OPC; RPTR (ONID) NEXT);
COMMENT: STATUS holds the Kill and Enable bits.
OPC is the On-program counter.
NEXT is used for chaining of ons;
RCLASS PROCESSID (INTEGER PC, DEPENDENTS, WAITTYPE;
RPTR(PROCESSID) NEXT, MOTHER; RPTR(ONID) RUNONS, WAITONS);
COMMENT: PC=program counter. DEPENDENTS=count.
WAITTYPE=0 for run, 1 for dependent wait, 2 for event wait.
NEXT used for queuing. MOTHER points to mother.
RUNONS is list of dependent on-monitors.
WAITONS is list of dependent on-monitors active only during wait;
RCLASS QUEUE (RPTR(PROCESSID) HEAD, TAIL);
RPTR (PROCESSID) CURRENT;
RPTR(QUEUE) RUNQUEUE;
DEFINE ENABLE = "'1";
DEFINE KILL = "'2";
PROCEDURE INITIALIZE;
BEGIN
QUEUE:HEAD(RUNQUEUE) ← NEW_RECORD (PROCESSID);
FOREACH ON-MONITOR DO
BEGIN
X ← NEW_RECORD (ONID);
ONID:NEXT(X) ← RNULL;
ONID:STATUS(X) ← 0;
ONID:OPC(X) ← OPC;
END;
END;
PROCEDURE ENQUEUE(RPTR(QUEUE) WHERE; RPTR(PROCESSID) NEW);
BEGIN
COMMENT: Puts a process on a queue. QUEUE tells which
queue. NEW is the process id;
QUEUE:TAIL(WHERE) ← PROCESSID:NEXT(QUEUE:TAIL(WHERE)) ← NEW;
PROCESSID:NEXT(QUEUE:TAIL(WHERE)) ← RNULL;
END;
RPTR(PROCESSID) PROCEDURE DEQUEUE (RPTR(QUEUE) WHERE);
BEGIN
COMMENT: Returns head of queue, which is removed;
RPTR(PROCESSID) ANSWER;
IF QUEUE:HEAD(WHERE) = QUEUE:TAIL(WHERE)
THEN RETURN(RNULL); COMMENT: Empty queue;
ANSWER ← PROCESSID:NEXT(QUEUE:HEAD(WHERE));
IF (PROCESSID:NEXT(QUEUE:HEAD(WHERE)) ← PROCESSID:NEXT(ANSWER)) = RNULL
THEN QUEUE:TAIL(WHERE) ← QUEUE:HEAD(WHERE);
RETURN(ANSWER);
END;
PROCEDURE SPROUT (IPC);
BEGIN
COMMENT: IPC is the interpreter program counter.
The effect is to put the new interpreter in the run-queue;
RPTR (PROCESSID) NEW;
↑;
NEW ← NEW_RECORD (PROCESSID);
PROCESSID:PC(NEW) ← IPC;
PROCESSID:DEPENDENTS(NEW) ← 0;
PROCESSID:WAITTYPE(NEW) ← 0;
PROCESSID:MOTHER(NEW) ← CURRENT;
PROCESSID:DEPENDENTS(CURRENT) ← PROCESSID:DEPENDENTS(CURRENT) + 1
ENQUEUE(RUNQUEUE,NEW);
↓;
END;
PROCEDURE TERMINATE;
BEGIN COMMENT: Terminates the caller;
RPTR(PROCESSID) MOM;
RPTR(ONID) VICTIM, OLD;
INTEGER TEMP;
↑;
IF PROCESSID:DEPENDENTS(CURRENT) ≠ 0
THEN BEGIN COMMENT: This should never happen;
ERROR("ACTIVE PROCESS DEPENDS ON BLOCK BEING EXITED");
WAIT;
END;
MOM ← PROCESSID:MOTHER(CURRENT);
TEMP ← PROCESSID:DEPENDENTS(MOM) ← PROCESSID:DEPENENTS(MOM) - 1;
IF PROCESSID:WAITTYPE(MOM)=1 AND TEMP=0
THEN BEGIN COMMENT: Must awaken mom;
VICTIM ← PROCESSID:WAITONS(MOM);
PROCESSID:WAITONS(MOM) ← RNULL;
WHILE VICTIM ≠ RNULL DO
BEGIN COMMENT: Kill mom's wait ons;
DISABLE(VICTIM);
OLD ← VICTIM;
VICTIM ← ONID:NEXT(VICTIM);
ONID:NEXT(OLD) ← RNULL;
END;
PROCESSID:WAITTYPE(MOM) ← 0;
ENQUEUE(RUNQUEUE,MOM);
END;
VICTIM ← PROCESSID:RUNONS(CURRENT);
PROCESSID:RUNONS(CURRENT) ← RNULL;
WHILE VICTIM ≠ RNULL DO
BEGIN COMMENT: Kill current's run ons;
DISABLE(VICTIM);
OLD ← VICTIM;
VICTIM ← ONID:NEXT(VICTIM);
ONID:NEXT(OLD) ← RNULL;
END;
CURRENT ← RNULL; COMMENT: explicit deallocate?;
↓;
JRST RESCHEDULE;
END;
PROCEDURE WAIT;
BEGIN COMMENT: Caller wishes to wait until all descendents have dismissed;
RPTR(ONID) DEB;
↑;
IF PROCESSID:DEPENDENTS(CURRENT) ≠ 0
THEN BEGIN COMMENT: Must wait;
PROCESSID:PC(CURRENT) ← <RETURN ADDRESS>;
PROCESSID:WAITTYPE(CURRENT) ← 1;
DEB ← PROCESSID:WAITONS(CURRENT);
WHILE DEB ≠ RNULL DO
BEGIN COMMENT: Enable all wait ons;
IF ONID:STATUS(DEB) LAND ENABLE = 0
THEN BEGIN
ONID:STATUS(DEB) ← ONID:STATUS(DEB) LAND ¬KILL;
PUSHJ (ONID:OPC(DEB));
END;
DEB ← NEXT(DEB);
END;
↓;
JRST RESCHEDULE;
END
ELSE ↓;
END;
PROCEDURE RUN_ENABLE (RPTR (ONID) MON);
BEGIN COMMENT: Wish to enable a run on monitor;
↑;
IF ONID:STATUS(MON) LAND ENABLE ≠ 0
THEN BEGIN ↓; RETURN END; COMMENT: Already going;
ONID:STATUS(MON) ← ONID:STATUS(MON) LAND ¬KILL;
IF ONID:NEXT(MON) = RNULL
THEN BEGIN COMMENT: Add this run on to list for Current;
ONID:NEXT(MON) ← PROCESSID:RUNONS(CURRENT);
PROCESSID:RUNONS(CURRENT) ← ONID;
END;
PUSHJ (ONID:OPC(MON));
↓;
END;
PROCEDURE WAIT_ENABLE (RPTR (ONID) MON);
BEGIN COMMENT: Wish to set up a wait on monitor;
↑;
IF ONID:STATUS(MON) LAND ENABLE ≠ 0
THEN BEGIN ↓; RETURN END; COMMENT: Already going;
IF ONID:NEXT(MON) = RNULL
THEN BEGIN COMMENT: Add this wait on to list for Current;
ONID:NEXT(MON) ← PROCESSID:WAITONS(CURRENT);
PROCESSID:WAITONS(CURRENT) ← ONID;
END;
↓;
END;
PROCEDURE DISABLE (RPTR(ONID) MON);
BEGIN
ONID:STATUS(MON) ← KILL;
END;
PROCEDURE RESCHEDULE;
BEGIN
↑;
IF CURRENT = RNULL
THEN BEGIN
WHILE RUNQUEUE = RNULL DO BEGIN ↓; ↑; END;
CURRENT ← DEQUEUE(RUNQUEUE);
PUSH NAME(CURRENT);
PUSH IPC(CURRENT);
↓;
PUSHJ INTERPRETER;
END;
ELSE ↓;
END;
DEPROACHES now in memo
SYSTEM USER FEATURES
The HAL system is intended to be a flexible tool for the
planning of complex assembly tasks by a skilled operator. This
planning has several phases: initial preparation of the program,
removing syntactic errors from the source code, trying the program
out, and fixing discoved bugs until the program works
satisfactorilly. The final stage is the production run of the
program, which can occur in a basically unsupervised mode. During
execution, however, it is still possible to interrupt the machine and
find out exactly where it is in the plan and debug it further. This
is useful for patching a program which over the course of a long
execution begins to "drift" from reality.
Thus, the user features can be divided roughly into these
parts:
PROGRAM FORMULATION
It is hoped that the HAL language described in some detail
earlier provides a clear and complete system in which to express
those manipulations necessary for the correct execution of an
assembly task. The structured concept of statement, made powerful by
the relatively unstructured concept of the on-monitor, should make
writing in HAL relatively easy.
One other way in which HAL can assist the programmer is that
she can have it read the current location of an arm and to use that
frame as a constant in her program. This makes programming by doing
possible. One way to put together a simple program is merely to move
the arm manually to the different locations desired, have the system
remember those locations, and then type in appropriate motion
commands between these points.
PROGRAM COMPILATION
The supervisor is the key to this and the following features;
it allows the user to oversee the progress of her program and fix
errors as they arise. There is a simple "supervisor language"
intended for communication with the HAL system. Some of its commands
are demonstrated in the sample dialog given earlier. One of the
commands causes compilation to begin; the parser is directed to read
some file. One option is to have console input itself used to enter
the source code; this is especially useful in causing the arm to do
something immediately. When the parser finds a syntax error, it will
give an error message, and several options will in general be
available. These include aborting the compilation, skipping to the
ebd of the current statement, editing the line with the system line
editor (after which the entire statement will be reparsed, if
possible), and temporarily switching to a text editor to fix the
problem (after which the entire program must be reparsed).
The expander can also find errors; these are usually semantic
errors, like generating a move to a point with undefined planning
value, not supplying enough information to a high-level primitive, or
attempting to move the same arm simultaneously in two blocks of code.
In those cases where the problem is one of insufficient information,
the expander will prompt for more, and, if possible, continue. The
user may decide not to supply that information, and in that case, the
offending statement is flushed. Some errors are so drastic as to
require complete recompilation; the user is always given the option
of switching to a text editor for major modifications.
There is a limited number of errors which the trajectory
calculator is capable of discovering. These mostly involve motions
beyond the capability of the manipulators involved. Options to the
user include making the best legal trajectory possible, causing the
trajectory to be slowed down, and putting in a null trajectory.
PROGRAM EXECUTION
After a program has been compiled, it resides on disk as a
load module. Any number of load modules can be loaded together; the
principal restriction is that each of them be a "top level" program.
As mentioned earlier, the loader will resolve calls between the large
(planning) computer and the small (execution) computer for those
functions which the user has decided require the computational
ability found only on the large computer.
Execution is initiated by another supervisor command issued
by the user. While the mini is executing the program, the user can
cause an interruption and examine values within the runtime system,
and modify them if she wishes. It is also possible to examine the
code generated by the compiler and modify it, but this is most likely
only of interest to system programmers. Sizeable patches require
recompilation.
Sometimes hardware difficulties will cause abrupt termination
of the program; these often are due to runtime trajectory
modifications overstraining the hardware. After issuing an error
message to the user, the system behaves just as it would should it
have been interrupted manually.
It is possible, during one of these "breaks", to request that
the entire world be saved. This causes all runtime values to be
written out into a safe place, along with the current attachment
structure and the current program counters. There are several uses
for this feature: it allows the debugging of the task to stop
temporarily and to be resumed later. More important, it plants a
"safe point" in the code, so that if an error should occur later, it
is possible to back up the program to a point at which everything was
still working.
Programs which have been completely debugged can be
"unloaded", that is, saved in a dump file for execution any time in
the future.